home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / teco / part03 < prev    next >
Encoding:
Internet Message Format  |  1987-03-11  |  52.2 KB

  1. Subject:  v09i030:  A TECO text editor, Part03/04
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: genrad!mlf
  6. Mod.sources: Volume 9, Issue 30
  7. Archive-name: teco/Part03
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If this archive is complete, you will see the message:
  13. #        "End of archive 3 (of 4)."
  14. # Contents:  te_exec1.c te_exec2.c
  15. # Wrapped by rs@mirror on Thu Mar 12 19:54:32 1987
  16. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  17. echo shar: Extracting \"te_exec1.c\" \(21012 characters\)
  18. if test -f te_exec1.c ; then 
  19.   echo shar: Will not over-write existing file \"te_exec1.c\"
  20. else
  21. sed "s/^X//" >te_exec1.c <<'END_OF_te_exec1.c'
  22. X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum                        */
  23. X/* This program and its components belong to GenRad Inc, Concord MA 01742    */
  24. X/* They may be copied if this copyright notice is included                    */
  25. X
  26. X/* te_exec1.c   continue executing commands   1/8/87 */
  27. X#include "te_defs.h"
  28. X
  29. Xexec_cmds1()
  30. X    {
  31. X    char command;                    /* command character */
  32. X    int cond;                        /* conditional in progress */
  33. X
  34. X    switch (command = mapch_l[cmdc])
  35. X        {
  36. X/* operators */
  37. X
  38. X        case '+':
  39. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  40. X            esp->flag1 = 0;
  41. X            esp->op = OP_ADD;
  42. X            break;
  43. X
  44. X        case '-':
  45. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  46. X            esp->flag1 = 0;
  47. X            esp->op = OP_SUB;
  48. X            break;
  49. X
  50. X        case '*':
  51. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  52. X            esp->flag1 = 0;
  53. X            esp->op = OP_MULT;
  54. X            break;
  55. X
  56. X        case '/':
  57. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  58. X            esp->flag1 = 0;
  59. X            esp->op = OP_DIV;
  60. X            break;
  61. X
  62. X        case '&':
  63. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  64. X            esp->flag1 = 0;
  65. X            esp->op = OP_AND;
  66. X            break;
  67. X
  68. X        case '#':
  69. X            esp->exp = (esp->flag1) ? esp->val1 : 0;
  70. X            esp->flag1 = 0;
  71. X            esp->op = OP_OR;
  72. X            break;
  73. X
  74. X        case ')':
  75. X            if ((!esp->flag1) || (esp <= &estack[0])) ERROR(E_NAP);
  76. X            --esp;
  77. X            esp->val1 = (esp+1)->val1;    /* carry value from inside () */
  78. X            esp->flag1 = 1;
  79. X            break;
  80. X         case ',':
  81. X            if (!esp->flag1) ERROR(E_NAC);
  82. X            else esp->val2 = esp->val1;
  83. X            esp->flag2 = 1;
  84. X            esp->flag1 = 0;
  85. X            break;
  86. X
  87. X        case CTL (_):
  88. X            if (!esp->flag1) ERROR(E_NAB);
  89. X            else esp->val1 = ~esp->val1;
  90. X            break;
  91. X
  92. X/* radix control */
  93. X
  94. X        case CTL (D):
  95. X            ctrl_r = 10;
  96. X            esp->flag1 = 0;
  97. X            esp->op = OP_START;
  98. X            break;
  99. X
  100. X        case CTL (O):
  101. X            ctrl_r = 8;
  102. X            esp->flag1 = 0;
  103. X            esp->op = OP_START;
  104. X            break;
  105. X
  106. X        case CTL (R):
  107. X            if (!esp->flag1)    /* fetch it */
  108. X                {
  109. X                esp->val1 = ctrl_r;
  110. X                esp->flag1 = 1;
  111. X                }
  112. X            else
  113. X                {
  114. X                if ((esp->val1 != 8) && (esp->val1 != 10) && (esp->val1 != 16)) ERROR(E_IRA);
  115. X                ctrl_r = esp->val1;
  116. X                esp->flag1 = 0;
  117. X                esp->op = OP_START;
  118. X                }
  119. X            break;
  120. X
  121. X/* other commands */
  122. X
  123. X        case CTL (C):            /* 1 ^C stops macro execution, 2 exit */
  124. X            if (peekcmdc(CTL (C))) exitflag = -1;        /* 2 ^C: stop execution and exit */
  125. X            else if (msp <= &mstack[0]) exitflag = 1;    /* 1 ^C: in command string: stop execution */
  126. X            else --msp;                                    /*         in a macro - pop it */
  127. X            break;
  128. X
  129. X        case CTL (X):            /* search mode flag */
  130. X            set_var(&ctrl_x);
  131. X            break;
  132. X
  133. X        case 'e':
  134. X            do_e();
  135. X            break;
  136. X
  137. X        case 'f':
  138. X            do_f();
  139. X            break;
  140. X /* macro call, iteration, conditional */
  141. X
  142. X        case 'm':                /* macro call */
  143. X            mm = getqspec(0, getcmdc(trace_sw));    /* read the macro name */
  144. X            if (msp > &mstack[MSTACKSIZE-1]) ERROR(E_PDO);    /* check room for another level */
  145. X            ++msp;                    /* push stack */
  146. X            cptr.p = qreg[mm].f;    /* to stack entry, put q-reg text start */
  147. X            cptr.flag = cptr.c = cptr.dot = 0;    /* initial char position, iteration flag */
  148. X            cptr.z = qreg[mm].z;    /* number of chars in macro */
  149. X            break;
  150. X
  151. X        case '<':                /* begin iteration */
  152. X            if ((esp->flag1) && (esp->val1 <= 0))        /* if this is not to be executed */
  153. X                find_enditer();                            /* just skip the intervening stuff */
  154. X            else
  155. X                {
  156. X                if (!cptr.il)        /* does this macro have an iteration list? */
  157. X                    {
  158. X                    cptr.il = (struct is *) get_dcell();    /* no, make one for it */
  159. X                    cptr.il->b = NULL;                        /* with NULL reverse pointer */
  160. X                    }
  161. X                else if (cptr.flag & F_ITER)        /* is there an iteration in process? */
  162. X                    {
  163. X                    if (!cptr.il->f)                /* yes, if it has no forward pointer */
  164. X                        {
  165. X                        cptr.il->f = (struct is *) get_dcell();        /* append a cell to the iteration list */
  166. X                        cptr.il->f->b = cptr.il;                    /* and link it in */
  167. X                        }
  168. X                    cptr.il = cptr.il->f;                        /* and advance the iteration list pointer to it */
  169. X                    }
  170. X                cptr.flag |= F_ITER;                /* set iteration flag */
  171. X                cptr.il->p = cptr.p;                /* save start of iteration */
  172. X                cptr.il->c = cptr.c;
  173. X                cptr.il->dot = cptr.dot;
  174. X                if (cptr.il->dflag = esp->flag1)    /* if there is an argument, set the "def iter" flag */
  175. X                    {
  176. X                    cptr.il->count = esp->val1;        /* save the count */
  177. X                    esp->flag1 = 0;                    /* and consume the arg */
  178. X                    }
  179. X                }
  180. X            break;
  181. X
  182. X        case '>':                /* end iteration */
  183. X            if (!(cptr.flag & F_ITER)) ERROR(E_BNI);        /* error if > not in iteration */
  184. X            pop_iteration(0);        /* decrement count and pop conditionally */
  185. X            esp->flag1 = esp->flag2 = 0;    /* consume arguments */
  186. X            esp->op = OP_START;
  187. X            break;
  188. X
  189. X        case ';':                /* semicolon iteration exit */
  190. X            if (!(cptr.flag &F_ITER)) ERROR(E_SNI);        /* error if ; not in iteration */
  191. X            if ( ( ((esp->flag1) ? esp->val1 : srch_result) >= 0) ? (!colonflag) : colonflag)    /* if exit */
  192. X                {
  193. X                find_enditer();            /* get to end of iteration */
  194. X                pop_iteration(1);        /* and pop unconditionally */
  195. X                }
  196. X            esp->flag1 = colonflag = 0;        /* consume arg and colon */
  197. X            esp->op = OP_START;
  198. X            break;
  199. X /* conditionals */
  200. X
  201. X        case '"':
  202. X            if (!esp->flag1) ERROR(E_NAQ);        /* must be an argument */
  203. X            esp->flag1 = 0;                    /* consume argument */
  204. X            esp->op = OP_START;
  205. X            switch (mapch_l[getcmdc(trace_sw)])
  206. X                {
  207. X                case 'a':
  208. X                    cond = isalpha(esp->val1);
  209. X                    break;
  210. X
  211. X                case 'c':
  212. X                    cond = isalpha(esp->val1) | (esp->val1 == '$') | (esp->val1 == '.');
  213. X                    break;
  214. X
  215. X                case 'd':
  216. X                    cond = isdigit(esp->val1);
  217. X                    break;
  218. X
  219. X                case 'e':
  220. X                case 'f':
  221. X                case 'u':
  222. X                case '=':
  223. X                    cond = !(esp->val1);
  224. X                    break;
  225. X
  226. X                case 'g':
  227. X                case '>':
  228. X                    cond = (esp->val1 > 0);
  229. X                    break;
  230. X
  231. X                case 'l':
  232. X                case 's':
  233. X                case 't':
  234. X                case '<':
  235. X                    cond = (esp->val1 < 0);
  236. X                    break;
  237. X
  238. X                case 'n':
  239. X                    cond = esp->val1;
  240. X                    break;
  241. X
  242. X                case 'r':
  243. X                    cond = isalnum(esp->val1);
  244. X                    break;
  245. X
  246. X                case 'v':
  247. X                    cond = islower(esp->val1);
  248. X                    break;
  249. X
  250. X                case 'w':
  251. X                    cond = isupper(esp->val1);
  252. X                    break;
  253. X
  254. X                default:
  255. X                    ERROR(E_IQC);
  256. X                }
  257. X             if (!cond)            /* if this conditional isn't satisfied */
  258. X                {
  259. X                for (ll = 1; ll > 0;)        /* read to matching | or ' */
  260. X                    {
  261. X                    while ((skipto(0) != '"') && (skipc != '|') && (skipc != '\''));    /* skip chars */
  262. X                    if (skipc == '"')       ++ll;    /* start another level */
  263. X                    else if (skipc == '\'') --ll;    /* end a level */
  264. X                    else if (ll == 1) break;        /* "else" (|): if on this level, start executing */
  265. X                    }
  266. X                }
  267. X            break;
  268. X
  269. X        case '\'':                /* end of conditional */
  270. X            break;                /* ignore it if executing */
  271. X
  272. X        case '|':                /* "else" clause */
  273. X            for (ll = 1; ll > 0;)            /* skip to matching ' */
  274. X                {
  275. X                while ((skipto(0) != '"') && (skipc != '\''));    /* skip chars */
  276. X                if (skipc == '"') ++ll;            /* start another level */
  277. X                else             --ll;            /* end a level */
  278. X                }
  279. X            break;
  280. X /* q-register numeric operations */
  281. X
  282. X        case 'u':
  283. X            if (!esp->flag1) ERROR(E_NAU);    /* error if no arg */
  284. X            else qreg[getqspec(0, getcmdc(trace_sw))].v = esp->val1;
  285. X            esp->flag1 = esp->flag2;        /* command's "value" is 2nd arg */
  286. X            esp->val1 = esp->val2;
  287. X            esp->flag2 = 0;                    /* clear 2nd arg */
  288. X            esp->op = OP_START;
  289. X            break;
  290. X
  291. X        case 'q':        /* Qn is numeric val, :Qn is # of chars, mQn is mth char */
  292. X            mm = getqspec((colonflag || esp->flag1), getcmdc(trace_sw));        /* read register name */
  293. X            if (!(esp->flag1))
  294. X                {
  295. X                esp->val1 = (colonflag) ? qreg[mm].z : qreg[mm].v;
  296. X                esp->flag1 = 1;
  297. X                }
  298. X            else        /* esp->flag1 is already set */
  299. X                {
  300. X                if ((esp->val1 >= 0) && (esp->val1 < qreg[mm].z))    /* char subscript within range? */
  301. X                    {
  302. X                    for (ll = 0, aa.p = qreg[mm].f; ll < (esp->val1 / CELLSIZE); ll++) aa.p = aa.p->f;
  303. X                    esp->val1 = (int) aa.p->ch[esp->val1 % CELLSIZE];
  304. X                    }
  305. X                else esp->val1 = -1;    /* char position out of range */
  306. X                esp->op = OP_START;        /* consume argument */
  307. X                }
  308. X            colonflag = 0;
  309. X            break;
  310. X
  311. X        case '%':
  312. X            esp->val1 = (qreg[getqspec(0, getcmdc(trace_sw))].v += get_value(1));    /* add to q reg */
  313. X            esp->flag1 = 1;
  314. X            break;
  315. X /* move pointer */
  316. X
  317. X        case 'c':
  318. X            if (((tdot = dot + get_value(1)) < 0) || (tdot > z))
  319. X                ERROR(E_POP);    /* add arg to dot, default 1 */
  320. X            else dot = tdot;
  321. X            esp->flag2 = 0;
  322. X            break;
  323. X
  324. X        case 'r':
  325. X            if (((tdot = dot - get_value(1)) < 0) || (tdot > z))
  326. X                ERROR(E_POP);    /* add arg to dot, default 1 */
  327. X            else dot = tdot;
  328. X            esp->flag2 = 0;
  329. X            break;
  330. X
  331. X        case 'j':
  332. X            if (((tdot = get_value(0)) < 0) || (tdot > z))
  333. X                ERROR(E_POP);    /* add arg to dot, default 1 */
  334. X            else dot = tdot;
  335. X            esp->flag2 = 0;
  336. X            break;
  337. X
  338. X        case 'l':
  339. X            dot += lines(get_value(1));
  340. X            break;
  341. X
  342. X/* number of chars until nth line feed */
  343. X
  344. X        case CTL (Q):
  345. X            esp->val1 = lines(get_value(1));
  346. X            esp->flag1 = 1;
  347. X            break;
  348. X
  349. X/* print numeric value */
  350. X
  351. X        case '=':
  352. X            if (!esp->flag1) ERROR(E_NAE);    /* error if no arg */
  353. X            else
  354. X                {
  355. X                if (peekcmdc('='))        /* at least one more '=' */
  356. X                    {
  357. X                    getcmdc(trace_sw);        /* read past it */
  358. X                    if (peekcmdc('='))        /* another? */
  359. X                        {
  360. X                        getcmdc(trace_sw);            /* yes, read it too */
  361. X                        printf("%x", esp->val1);    /* print in hex */
  362. X                        }
  363. X                    else printf("%o", esp->val1);    /* print in octal */
  364. X                    }
  365. X                else printf("%d", esp->val1);
  366. X                if (!colonflag) crlf();
  367. X                esp->flag1 = esp->flag2 =  colonflag = 0;
  368. X                esp->op = OP_START;
  369. X                if (!WN_scroll) window(WIN_REDRAW);            /* if not in scroll mode, force full redraw on next refresh */
  370. X                }
  371. X            break;
  372. X /* insert text */
  373. X
  374. X        case TAB:                    /* insert tab, then text */
  375. X            if (ez_val & EZ_NOTABI) break;        /* tab disabled */
  376. X            if (esp->flag1) ERROR(E_IIA);        /* can't have arg */
  377. X
  378. X        case 'i':                    /* insert text at pointer */
  379. X            term_char = (atflag) ? getcmdc(trace_sw) : ESC;        /* set terminator */
  380. X            if (esp->flag1)        /* if a nI$ command */
  381. X                {
  382. X                if (!peekcmdc(term_char)) ERROR(E_IIA);    /* next char must be term */
  383. X                insert1();            /* first part of insert */
  384. X                bb.p->ch[bb.c] = esp->val1 & 0177;        /* insert character */
  385. X                fwdcx(&bb);            /* advance pointer and extend buffer if necessary */
  386. X                ins_count = 1;        /* save string length */
  387. X                esp->op = OP_START;    /* consume argument */
  388. X                }
  389. X            else                    /* not a nI command: insert text */
  390. X                {
  391. X                insert1();            /* initial insert operations */
  392. X
  393. X                if (command == TAB)            /* TAB insert puts in a tab first */
  394. X                    {
  395. X                    bb.p->ch[bb.c] = TAB;    /* insert a tab */
  396. X                    fwdcx(&bb);                /* advance pointer and maybe extend buffer */
  397. X                    }
  398. X                moveuntil(&cptr, &bb, term_char, &ins_count, cptr.z - cptr.dot, trace_sw);    /* copy cmd str -> buffer */
  399. X                if (command == TAB) ++ins_count;    /* add 1 if a tab inserted */
  400. X                cptr.dot += ins_count;    /* indicate advance over that many chars */
  401. X                }
  402. X            insert2(ins_count);        /* finish insert */
  403. X            getcmdc(trace_sw);        /* flush terminating char */
  404. X            colonflag = atflag = esp->flag1 = esp->flag2 = 0;    /* clear args */
  405. X            break;
  406. X
  407. X/* type text from text buffer */
  408. X    
  409. X        case 't':
  410. X            for (ll = line_args(0, &aa); ll > 0; ll--)    /* while there are chars to type */
  411. X                {
  412. X                type_char(aa.p->ch[aa.c]);
  413. X                fwdc(&aa);
  414. X                }
  415. X            if (!WN_scroll) window(WIN_REDRAW);            /* if not in scroll mode, force full redraw on next refresh */
  416. X            break;
  417. X
  418. X        case 'v':
  419. X            if ((ll = get_value(1)) > 0)        /* arg must be positive */
  420. X                {
  421. X                mm = lines(1 - ll);                    /* find start */
  422. X                nn = lines(ll) - mm;                /* and number of chars */
  423. X                set_pointer(dot + mm, &aa);            /* pointer to start of text */
  424. X                for (; nn > 0; nn--)                /* as above */
  425. X                    {
  426. X                    type_char(aa.p->ch[aa.c]);
  427. X                    fwdc(&aa);
  428. X                    }
  429. X                }
  430. X            if (!WN_scroll) window(WIN_REDRAW);            /* if not in scroll mode, force full redraw on next refresh */
  431. X            break;
  432. X /* type text from command string */
  433. X
  434. X        case CTL (A):
  435. X            term_char = (atflag) ? getcmdc(trace_sw) : CTL(A);        /* set terminator */
  436. X            while (getcmdc(0) != term_char) type_char(cmdc);    /* output chars */
  437. X            atflag = colonflag = esp->flag2 = esp->flag1 = 0;
  438. X            esp->op = OP_START;
  439. X            if (!WN_scroll) window(WIN_REDRAW);            /* if not in scroll mode, force full redraw on next refresh */
  440. X            break;
  441. X
  442. X    /* delete text */
  443. X
  444. X        case 'd':
  445. X            if (!esp->flag2)                /* if only one argument */
  446. X                {
  447. X                delete1(get_value(1));            /* delete chars (default is 1) */
  448. X                break;
  449. X                }                /* if two args, fall through to treat m,nD as m,nK */
  450. X
  451. X        case 'k':                    /* delete lines or chars */
  452. X            ll = line_args(1, &aa);    /* aa points to start, ll chars, leave dot at beginning */
  453. X            delete1(ll);            /* delete ll chars */
  454. X            break;
  455. X
  456. X/* q-register text loading commands */
  457. X
  458. X        case CTL (U):
  459. X            mm = getqspec(0, getcmdc(trace_sw));
  460. X            if (!colonflag)            /* X, ^U commands destroy previous contents */
  461. X                {
  462. X                dly_free_blist(qreg[mm].f);
  463. X                qreg[mm].f = NULL;
  464. X                qreg[mm].z = 0;
  465. X                }
  466. X            term_char = (atflag) ? getcmdc(trace_sw) : ESC;        /* set terminator */
  467. X            atflag = 0;            /* clear flag */
  468. X
  469. X            if ((esp->flag1) || (!peekcmdc(term_char)))        /* if an arg or a nonzero insert, find register */
  470. X                {
  471. X                make_buffer(&qreg[mm]);            /* attach a text buffer to the q register */
  472. X                for (bb.p = qreg[mm].f; bb.p->f != NULL; bb.p = bb.p->f);    /* find end of reg */
  473. X                bb.c = (colonflag) ? qreg[mm].z % CELLSIZE : 0;
  474. X                }
  475. X            if (!(esp->flag1))
  476. X                {
  477. X                moveuntil(&cptr, &bb, term_char, &ll, cptr.z - cptr.dot, trace_sw);
  478. X                cptr.dot += ll;            /* indicate advance over that many chars */
  479. X                qreg[mm].z += ll;        /* update q-reg char count */
  480. X                getcmdc(trace_sw);        /* skip terminator */
  481. X                }
  482. X            else
  483. X                {
  484. X                if (getcmdc(trace_sw) != term_char) ERROR(E_IIA);    /* must be zero length string */
  485. X                bb.p->ch[bb.c] = esp->val1;                /* store char */
  486. X                fwdcx(&bb);                /* extend the register */
  487. X                ++qreg[mm].z;
  488. X                esp->flag1 = 0;            /* consume argument */
  489. X                }
  490. X            colonflag = 0;
  491. X            break;
  492. X         case 'x':
  493. X            mm = getqspec(0, getcmdc(trace_sw));
  494. X            if (!colonflag)            /* X, ^U commands destroy previous contents */
  495. X                {
  496. X                dly_free_blist(qreg[mm].f);        /* return, but delayed (in case executing now) */
  497. X                qreg[mm].f = NULL;
  498. X                qreg[mm].z = 0;
  499. X                }
  500. X
  501. X            if (ll = line_args(0, &aa))        /* read args and move chars, if any */
  502. X                {
  503. X                make_buffer(&qreg[mm]);            /* attach a text buffer to the q register */
  504. X                for (bb.p = qreg[mm].f; bb.p->f != NULL; bb.p = bb.p->f);    /* find end of reg */
  505. X                bb.c = (colonflag) ? qreg[mm].z % CELLSIZE : 0;
  506. X
  507. X                movenchars(&aa, &bb, ll);
  508. X                qreg[mm].z += ll;        /* update q-reg char count */
  509. X                }
  510. X            colonflag = 0;
  511. X            break;
  512. X
  513. X        case 'g':                /* get q register */
  514. X            if (qreg[mm = getqspec(1, getcmdc(trace_sw))].z)    /* if any chars in it */
  515. X                {
  516. X                cc.p = qreg[mm].f;        /* point cc to start of reg */
  517. X                cc.c = 0;
  518. X                if (colonflag)        /* :Gx types q-reg */
  519. X                    {
  520. X                    for (ll = qreg[mm].z; ll > 0; ll--)
  521. X                        {
  522. X                        type_char(cc.p->ch[cc.c]);    /* type char */
  523. X                        fwdc(&cc);
  524. X                        }
  525. X                    }
  526. X                else
  527. X                    {
  528. X                    insert1();                /* set up for insert */
  529. X                    movenchars(&cc, &bb, qreg[mm].z);    /* copy q reg text */
  530. X                    insert2(qreg[mm].z);    /* finish insert */
  531. X                    }
  532. X                }
  533. X            colonflag = 0;
  534. X            break;
  535. X /* q-register push and pop */
  536. X
  537. X        case '[':
  538. X            if (qsp > &qstack[QSTACKSIZE-1]) ERROR(E_PDO);        /* stack full */
  539. X            else
  540. X                {
  541. X                make_buffer(++qsp);        /* increment stack ptr and put a text buffer there */
  542. X                mm = getqspec(1, getcmdc(trace_sw));        /* get the q reg name */
  543. X
  544. X                aa.p = qreg[mm].f;            /* point to the q register */
  545. X                aa.c = 0;
  546. X                bb.p = qsp->f;                /* point to the new list */
  547. X                bb.c = 0;
  548. X                movenchars(&aa, &bb, qreg[mm].z);    /* copy the text */
  549. X                qsp->z = qreg[mm].z;        /* and the length */
  550. X                qsp->v = qreg[mm].v;        /* and the value */
  551. X                }
  552. X            break;
  553. X
  554. X        case ']':
  555. X            mm = getqspec(1, getcmdc(trace_sw));        /* get reg name */
  556. X            if (qsp < &qstack[0])                /* if stack empty */
  557. X                {
  558. X                if (colonflag)                    /* :] returns 0 */
  559. X                    {
  560. X                    esp->flag1 = 1;
  561. X                    esp->val1 = 0;
  562. X                    colonflag = 0;
  563. X                    }
  564. X                else ERROR(E_CPQ);                /* ] makes an error */
  565. X                }
  566. X            else                                    /* stack not empty */
  567. X                {
  568. X                free_blist(qreg[mm].f);            /* return orig contents of reg */
  569. X                qreg[mm].f = qsp->f;            /* substitute stack entry */
  570. X                qsp->f->b = (struct buffcell *) &qreg[mm];
  571. X                qsp->f = NULL;                    /* null out stack entry */
  572. X                qreg[mm].z = qsp->z;
  573. X                qreg[mm].v = qsp->v;
  574. X                if (colonflag)
  575. X                    {
  576. X                    esp->flag1 = 1;                /* :] returns -1 */
  577. X                    esp->val1 = -1;
  578. X                    colonflag = 0;
  579. X                    }
  580. X                --qsp;
  581. X                }
  582. X            break;
  583. X         case '\\':
  584. X            if (!(esp->flag1))        /* no argument; read number */
  585. X                {
  586. X                ll = esp->val1 = 0;            /* sign flag and initial value */
  587. X                for (ctrl_s = 0; dot <= z; dot++, ctrl_s--)        /* count digits; don't read beyond buffer */
  588. X                    {
  589. X                    set_pointer(dot, &aa);    /* point to dot */
  590. X                    if ((aa.p->ch[aa.c] == '+') || (aa.p->ch[aa.c] == '-'))
  591. X                        {
  592. X                        if (ll) break;        /* second sign: quit */
  593. X                        else ll = aa.p->ch[aa.c];    /* first sign: save it */
  594. X                        }
  595. X                    else
  596. X                        {
  597. X                        if (ctrl_r != 16)    /* octal or decimal */
  598. X                            {                    /* stop if not a valid digit */
  599. X                            if ((!isdigit(aa.p->ch[aa.c])) || (aa.p->ch[aa.c] - '0' >= ctrl_r)) break;
  600. X                            esp->val1 = esp->val1 * ctrl_r + (aa.p->ch[aa.c] - '0');
  601. X                            }
  602. X                        else
  603. X                            {
  604. X                            if (!isxdigit(aa.p->ch[aa.c])) break;
  605. X                            esp->val1 = esp->val1 * 16 + ( (isdigit(aa.p->ch[aa.c])) ?
  606. X                                                aa.p->ch[aa.c] - '0' : mapch_l[aa.p->ch[aa.c]] - 'a' + 10);
  607. X                            }        /* end of hex */
  608. X                        }        /* end of digit processing */
  609. X                    }        /* end of "for each char" */
  610. X                if (ll == '-') esp->val1 = -(esp->val1);    /* if minus sign */
  611. X                esp->flag1 = 1;                /* always returns a value */
  612. X                }
  613. X
  614. X            else                    /* argument: insert it as a digit string */
  615. X                {
  616. X                if (ctrl_r == 8)        sprintf(t_bcell.ch, "%o", esp->val1);    /* print as digits */
  617. X                else if (ctrl_r == 10)    sprintf(t_bcell.ch, "%d", esp->val1);
  618. X                else                    sprintf(t_bcell.ch, "%x", esp->val1);
  619. X                insert1();            /* start insert */
  620. X                cc.p = &t_bcell;    /* point cc to the temp cell */
  621. X                cc.c = 0;
  622. X                moveuntil(&cc, &bb, '\0', &ins_count, CELLSIZE-1, 0);    /* copy the char string */
  623. X                insert2(ins_count);    /* finish the insert */
  624. X                esp->flag1 = 0;        /* consume argument */
  625. X                esp->op = OP_START;
  626. X                }
  627. X            break;
  628. X         case CTL (T):            /* type or input character */
  629. X            if (esp->flag1)        /* type */
  630. X                {
  631. X                type_char(esp->val1);
  632. X                esp->flag1 = 0;
  633. X                if (!WN_scroll) window(WIN_REDRAW);            /* if not in scroll mode, force full redraw on next refresh */
  634. X                }
  635. X            else
  636. X                {
  637. X                esp->val1 = (et_val & ET_NOWAIT) ? gettty_nowait() : gettty();
  638. X                if (!(et_val & ET_NOECHO) && (esp->val1 > 0) && !inp_noterm) type_char(esp->val1);        /* echo */
  639. X                esp->flag1 = 1;
  640. X                }
  641. X            break;
  642. X
  643. X/* search commands */
  644. X
  645. X        case 's':                    /* search within buffer */
  646. X            build_string(&sbuf);    /* read the search string */
  647. X            end_search (  do_search( setup_search() )  );        /* search */
  648. X            break;
  649. X
  650. X        case 'n':                    /* search through rest of file */
  651. X        case '_':
  652. X            do_nsearch(command);    /* call routine for N, _, E_ */
  653. X            break;
  654. X
  655. X        case 'o':                    /* branch to tag */
  656. X            do_o();
  657. X            break;
  658. X /* file I/O commands */
  659. X
  660. X        case 'p':                    /* write a page, get next (ignore args for now) */
  661. X            if (esp->flag1 && esp->flag2)    /* if two args */
  662. X                write_file(&aa, line_args(0, &aa), 0);        /* write spec'd buffer with no FF */
  663. X            else                            /* one arg */
  664. X                {
  665. X                for (ll = get_value(1);    ll > 0; ll--)    /* get count and loop */
  666. X                    {
  667. X                    set_pointer(0, &aa);
  668. X                    if (peekcmdc('w')) write_file(&aa, z, 1);    /* PW writes buffer, then FF */
  669. X                    else
  670. X                        {
  671. X                        write_file(&aa, z, ctrl_e);        /* P writes buffer, FF if read in, then gets next page */
  672. X                        dot = z = 0;            /* empty the buffer */
  673. X                        set_pointer(0, &aa);    /* set a pointer to the beginning of the buffer */
  674. X                        buff_mod = 0;            /* mark where new buffer starts */
  675. X                        esp->val1 = read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );    /* read a page */
  676. X                        esp->flag1 = colonflag;
  677. X                        }
  678. X                    }
  679. X                }
  680. X            if (peekcmdc('w')) getcmdc(trace_sw);        /* if a PW command, consume the W */
  681. X            colonflag = 0;
  682. X            break;
  683. X
  684. X        case 'y':                    /* get a page into buffer */
  685. X            if (esp->flag1) ERROR(E_NYA);
  686. X            if ((z) && (!(ed_val & ED_YPROT))) ERROR(E_YCA);    /* don't lose text */
  687. X            dot = z = 0;            /* clear buffer */
  688. X            set_pointer(0, &aa);    /* set a pointer to the beginning of the buffer */
  689. X            buff_mod = 0;            /* mark where new buffer starts */
  690. X            read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );        /* read a page */
  691. X            esp->flag1 = colonflag;
  692. X            esp->op = OP_START;
  693. X            colonflag = 0;
  694. X            break;
  695. X         case 'a':                    /* append, or ascii value */
  696. X            if (esp->flag1 && !colonflag)        /* ascii value */
  697. X                {
  698. X                ll = dot + esp->val1;        /* set a pointer before addr'd char */
  699. X                if ((ll >= 0) && (ll < z))    /* if character lies within buffer */
  700. X                    {
  701. X                    set_pointer(ll, &aa);
  702. X                    esp->val1 = (int) aa.p->ch[aa.c];    /* get char (flag already set) */
  703. X                    }
  704. X                else esp->val1 = -1;        /* otherwise return -1 */
  705. X                }
  706. X            else
  707. X                {
  708. X                set_pointer(z, &aa);                /* set pointer to end of buffer */
  709. X                if (z < buff_mod) buff_mod = z;            /* mark where new buffer starts */
  710. X                if (esp->flag1 && (esp->val1 <= 0)) ERROR(E_IAA);        /* neg or 0 arg to :A */
  711. X                read_file(&aa, &z, (esp->flag1 ? esp->val1 : 0) );        /* read a page */
  712. X                esp->flag1 = colonflag;
  713. X                colonflag = 0;
  714. X                }
  715. X            esp->op = OP_START;
  716. X            break;
  717. X
  718. X/* window commands */
  719. X
  720. X        case 'w':
  721. X            do_window(0);                    /* this stuff is with the window driver */
  722. X            break;
  723. X
  724. X        case CTL (W):
  725. X            do_window(1);                    /* this is, too */
  726. X            break;
  727. X
  728. X        default:
  729. X            ERROR(E_ILL);                    /* invalid command */
  730. X
  731. X        }        /* end of "switch" */
  732. X    return;        /* normal exit */
  733. X    }            /* end of exec_cmds1 */
  734. X
  735. END_OF_te_exec1.c
  736. if test 21012 -ne `wc -c <te_exec1.c`; then
  737.     echo shar: \"te_exec1.c\" unpacked with wrong size!?
  738. fi
  739. # end of overwriting check
  740. fi
  741. echo shar: Extracting \"te_exec2.c\" \(29256 characters\)
  742. if test -f te_exec2.c ; then 
  743.   echo shar: Will not over-write existing file \"te_exec2.c\"
  744. else
  745. sed "s/^X//" >te_exec2.c <<'END_OF_te_exec2.c'
  746. X/* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum                        */
  747. X/* This program and its components belong to GenRad Inc, Concord MA 01742    */
  748. X/* They may be copied if this copyright notice is included                    */
  749. X
  750. X/* te_exec2.c   process "E" and "F" commands   2/26/87 */
  751. X#include "te_defs.h"
  752. X#include <sys/wait.h>
  753. X
  754. Xstruct qh oldcstring;                        /* hold command string during ei */
  755. X
  756. X/* file stuff for input/output files */
  757. X
  758. Xstruct infiledata pi_file = { NULL, -1 };    /* input files */
  759. Xstruct infiledata si_file = { NULL, -1 };
  760. Xstruct infiledata *infile = &pi_file;        /* pointer to currently active input file structure */
  761. Xstruct outfiledata po_file, so_file;        /* output files */
  762. Xstruct outfiledata *outfile = &po_file;        /* pointer to currently active output file structure */
  763. XFILE *eisw;                                    /* indirect command file pointer */
  764. X
  765. X/* process E commands */
  766. X
  767. Xdo_e()
  768. X    {
  769. X    char c;                            /* temps */
  770. X    int old_var;
  771. X    FILE *t_eisw;
  772. X
  773. X    switch (mapch_l[getcmdc(trace_sw)])        /* read next character and dispatch */
  774. X        {    
  775. X
  776. X/* numeric values */
  777. X
  778. X        case 'd':                /* ED */
  779. X            set_var(&ed_val);
  780. X            break;
  781. X
  782. X        case 's':                /* ES */
  783. X            set_var(&es_val);
  784. X            break;
  785. X
  786. X        case 't':                /* ET */
  787. X            old_var = et_val;
  788. X            set_var(&et_val);
  789. X            et_val = (et_val & 0100651) | 001006;    /* force read_only bits */
  790. X            if ((et_val ^ old_var) & ET_TRUNC) window(WIN_REDRAW);        /* redraw if ET & 256 changes */
  791. X            break;
  792. X
  793. X        case 'u':                /* EU */
  794. X            set_var(&eu_val);
  795. X            break;
  796. X
  797. X        case 'v':                /* EV */
  798. X            set_var(&ev_val);
  799. X            break;
  800. X
  801. X        case 'z':                /* EZ */
  802. X            old_var = ez_val;
  803. X            set_var(&ez_val);
  804. X            tabmask = (ez_val & EZ_TAB4) ? 3 : 7;        /* set tab mask */
  805. X            if ((ez_val ^ old_var) & EZ_TAB4) window(WIN_REDRAW);        /* force window redisplay if EZ_TAB4 changes */
  806. X            break;
  807. X /* E_ search */
  808. X
  809. X        case '_':
  810. X            do_nsearch('e');
  811. X            break;
  812. X
  813. X/* file I/O commands */
  814. X
  815. X        case 'a':                /* set secondary output */
  816. X            outfile = &so_file;
  817. X            break;
  818. X
  819. X        case 'b':                /* open read/write with backup */
  820. X            if (!read_filename(1, 'r')) ERROR(E_NFI);    /* read the name */
  821. X            if (infile->fd) fclose(infile->fd);            /* close previously-open file */
  822. X            if (!(infile->fd = fopen(fbuf.f->ch, "r")))
  823. X                {
  824. X                if (!colonflag) ERROR(E_FNF);
  825. X                }
  826. X            else
  827. X                {
  828. X                if (outfile->fd) ERROR(E_OFO);        /* output file already open */
  829. X                for (ll = 0; ll < CELLSIZE; ll++)        /* save file string */
  830. X                    if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
  831. X                outfile->name_size = ll;
  832. X                outfile->t_name[ll++] = '.';
  833. X                outfile->t_name[ll++] = 't';
  834. X                outfile->t_name[ll++] = 'm';
  835. X                outfile->t_name[ll++] = 'p';
  836. X                outfile->t_name[ll] = '\0';
  837. X                if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
  838. X                outfile->bak = 1;    /* set backup mode */
  839. X                }
  840. X            infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
  841. X            esp->flag1 = colonflag;
  842. X            colonflag = 0;
  843. X            break;
  844. X
  845. X        case 'x':                /* finish edit and exit */
  846. X            exitflag = -1;
  847. X
  848. X            /* --- fall through to "EC" --- */
  849. X
  850. X        case 'c':                /* finish edit */
  851. X            set_pointer(0, &aa);                /* set a pointer to start of text buffer */
  852. X            write_file(&aa, z, ctrl_e);            /* write the current buffer */
  853. X            dot = z = 0;                        /* empty the buffer */
  854. X            window(WIN_REDRAW);                    /* force window redraw */
  855. X            if ((outfile->fd) && (infile->fd) && !(infile->eofsw))    /* if any input remaining, copy it to output */
  856. X                while ((c = getc(infile->fd)) != EOF) putc(c, outfile->fd);
  857. X
  858. X            /* --- fall through to "EF" --- */
  859. X         case 'f':                /* close output file */
  860. X            if (outfile->fd)    /* only if one is open */
  861. X                {
  862. X                fclose(outfile->fd);
  863. X                if (outfile->bak & 1)        /* if this is "backup" mode */
  864. X                    {
  865. X                    outfile->f_name[outfile->name_size] = '.';
  866. X                    outfile->f_name[outfile->name_size+1] = 'b';
  867. X                    outfile->f_name[outfile->name_size+2] = 'a';
  868. X                    outfile->f_name[outfile->name_size+3] = 'k';
  869. X                    outfile->f_name[outfile->name_size+4] = '\0';
  870. X                    outfile->t_name[outfile->name_size] = '\0';
  871. X                    rename(outfile->t_name, outfile->f_name);    /* rename orig file */
  872. X                    }
  873. X
  874. X                if (!(outfile->bak & 8))        /* if output file had ".tmp" extension */
  875. X                    {                                /* remove it */
  876. X                    outfile->t_name[outfile->name_size] = '.';
  877. X                    outfile->f_name[outfile->name_size] = '\0';
  878. X                    rename(outfile->t_name, outfile->f_name);    /* rename output */
  879. X                    }
  880. X                }
  881. X            outfile->fd = NULL;            /* mark "no output file open" */
  882. X            break;
  883. X
  884. X        case 'i':                /* indirect file execution */
  885. X            if (!read_filename(1, 'i'))        /* if no filename specified, reset command input */
  886. X                {
  887. X                if (eisw)        /* if ending a file execute, restore the previous "old command string" */
  888. X                    {
  889. X                    fclose(eisw);                /* return the file descriptor */
  890. X                    dly_free_blist(cbuf.f);        /* return the command string used by the file (after execution done) */
  891. X                    cbuf.f = oldcstring.f;
  892. X                    cbuf.z = oldcstring.z;
  893. X                    }
  894. X                t_eisw = 0;
  895. X                }
  896. X            else if (!(t_eisw = fopen(fbuf.f->ch, "r")))
  897. X                {
  898. X                if (!colonflag) ERROR(E_FNF);
  899. X                }
  900. X            else if (!eisw)            /* if this "ei" came from the command string */
  901. X                {
  902. X                oldcstring.f = cbuf.f;        /* save current command string */
  903. X                oldcstring.z = cbuf.z;
  904. X                cbuf.f = NULL;                /* and make it inaccessible to "rdcmd" */
  905. X                }
  906. X            if (eisw) fclose(eisw);            /* if a command file had been open, close it */
  907. X            esp->val1 = (eisw = t_eisw) ? -1 : 0;
  908. X            esp->flag1 = colonflag;
  909. X            colonflag = 0;
  910. X            esp->op = OP_START;
  911. X            break;
  912. X         case 'k':                /* kill output file */
  913. X            kill_output(outfile);
  914. X            break;
  915. X
  916. X        case 'p':                /* switch to secondary input */
  917. X            infile = &si_file;
  918. X            break;
  919. X
  920. X        case 'r':                /* specify input file, or switch to primary input */
  921. X            if (!read_filename(0, 'r')) infile = &pi_file;        /* no name, switch to primary input */
  922. X            else
  923. X                {
  924. X                if (infile->fd) fclose(infile->fd);                /* close previously-open file */
  925. X                if (!(infile->fd = fopen(fbuf.f->ch, "r")))
  926. X                    {
  927. X                    if (!colonflag) ERROR(E_FNF);
  928. X                    }
  929. X                }
  930. X            infile->eofsw = -1 - (esp->val1 = (infile->fd) ? -1 : 0);
  931. X            esp->flag1 = colonflag;
  932. X            colonflag = 0;
  933. X            esp->op = OP_START;
  934. X            break;
  935. X
  936. X        case 'w':                /* specify output file, or switch to primary output */
  937. X            if(!read_filename(0, 'w')) outfile = &po_file;
  938. X            else
  939. X                {
  940. X                if (outfile->fd) ERROR(E_OFO);        /* output file already open */
  941. X                for (ll = 0; ll < CELLSIZE; ll++)            /* save file string */
  942. X                    if ((outfile->t_name[ll] = outfile->f_name[ll] = fbuf.f->ch[ll]) == '\0') break;
  943. X                outfile->name_size = ll;
  944. X                if (!(ez_val & EZ_NOTMPFIL))            /* if not using literal output name */
  945. X                    {
  946. X                    outfile->t_name[ll++] = '.';        /* use provisional suffix ".tmp" */
  947. X                    outfile->t_name[ll++] = 't';
  948. X                    outfile->t_name[ll++] = 'm';
  949. X                    outfile->t_name[ll++] = 'p';
  950. X                    outfile->t_name[ll] = '\0';
  951. X                    }
  952. X                if (!(outfile->fd = fopen(outfile->t_name, "w"))) ERROR(E_COF);
  953. X                outfile->bak = ez_val & EZ_NOTMPFIL;            /* save "temp suffix" status */
  954. X                }
  955. X            break;
  956. X
  957. X        case 'y':                /* EY is Y without protection */
  958. X            if (esp->flag1) ERROR(E_NYA);
  959. X            dot = z = 0;            /* clear buffer */
  960. X            set_pointer(0, &aa);
  961. X            read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );
  962. X            esp->flag1 = colonflag;
  963. X            colonflag = 0;
  964. X            esp->op = OP_START;
  965. X            break;
  966. X         case 'n':                /* wildcard filespec */
  967. X            esp->val1 = do_en();
  968. X            esp->flag1 = colonflag;
  969. X            colonflag = 0;
  970. X            esp->op = OP_START;
  971. X            break;
  972. X
  973. X        case 'q':                /* system command */
  974. X            esp->val1 = do_eq();            /* do this as a separate routine */
  975. X            esp->flag1 = colonflag;
  976. X            colonflag = 0;
  977. X            esp->op = OP_START;
  978. X            break;
  979. X
  980. X        default:
  981. X            ERROR(E_IEC);
  982. X        }
  983. X    }
  984. X /* routine to execute a system command            */
  985. X/* this is done by forking off another process    */
  986. X/* to execute a shell via 'execl'                */
  987. X/* routine returns -1 if success, 0 if error in fork */
  988. X
  989. Xint do_eq()
  990. X    {
  991. X    int t;
  992. X    union wait status;
  993. X    char *pname;                /* pointer to name of shell */
  994. X    extern char *getenv();
  995. X
  996. X    build_string(&sysbuf);
  997. X    if (sysbuf.z > CELLSIZE-2) ERROR(E_STL);    /* command must fit within one cell */
  998. X    sysbuf.f->ch[sysbuf.z] = '\0';                /* store terminating null */
  999. X    if (!(pname = getenv("SHELL"))) ERROR(E_SYS);    /* read shell name */
  1000. X
  1001. X    if (!esp->flag1)            /* if not m,nEQ command */
  1002. X        {
  1003. X        if (win_data[7]) window(WIN_SUSP);            /* restore full screen */
  1004. X        crlf();                                        /* force characters out */
  1005. X        setup_tty(TTY_SUSP);                        /* restore terminal to normal mode */
  1006. X
  1007. X        t = vfork();                            /* fork a new process */
  1008. X        if (t == 0)                                /* if this is the child */
  1009. X            {
  1010. X            execl(pname, pname, "-c", &sysbuf.f->ch[0], 0);        /* call the named Unix routine */
  1011. X            printf("Error in 'execl'\n");        /* normally shouldn't get here */
  1012. X            exit(1);
  1013. X            }
  1014. X
  1015. X        while (wait(&status) != t);                /* if parent, wait for child to finish */
  1016. X        if (status.w_retcode) t = -1;            /* keep failure indication from child */
  1017. X        
  1018. X        setup_tty(TTY_RESUME);                        /* restore terminal to teco mode */
  1019. X        if (win_data[7])                    /* if window was enabled */
  1020. X            {
  1021. X            vt(VT_SETSPEC1);                /* set reverse video */
  1022. X            fputs("Type RETURN to continue", stdout);        /* require CR before continuing */
  1023. X            vt(VT_CLRSPEC);                    /* reverse video off */
  1024. X            while (gettty() != LF);
  1025. X            putchar(CR);                    /* back to beginning of line */
  1026. X            vt(VT_EEOL);                    /* and erase the message */
  1027. X            window(WIN_RESUME);                /* re-enable window */
  1028. X            window(WIN_REDRAW);                /* and make it redraw afterwards */
  1029. X            }
  1030. X        }
  1031. X
  1032. X    else t = do_eq1(pname);                    /* m,nEQ command */
  1033. X
  1034. X    return( (t == -1) ? 0 : -1);            /* return failure if fork failed or proc status nonzero */
  1035. X    }
  1036. X /* Execute m,nEQtext$ command.  Run "text" as a Unix command that    */
  1037. X/* receives its std input from chars m through n of teco's buffer.    */
  1038. X/* Output from the command is placed in Q#.                            */
  1039. X
  1040. Xint do_eq1(shell)
  1041. X    char *shell;            /* arg is pointer to shell name */
  1042. X    {
  1043. X    int ff, pipe_in[2], pipe_out[2];    /* fork result and two pipes */
  1044. X    FILE *xx_in, *xx_out;                /* std in and out for called process */
  1045. X    FILE *fdopen();
  1046. X    union wait status;
  1047. X
  1048. X    ll = line_args(1, &aa);        /* set aa to start of text, ll to number of chars */
  1049. X    dot += ll;                    /* set pointer at end of text */
  1050. X    ctrl_s = -ll;                /* set ^S to - # of chars */
  1051. X
  1052. X    if (pipe(pipe_out)) ERROR(E_SYS);    /* make input pipe; failure if can't */
  1053. X
  1054. X    if (win_data[7]) window(WIN_SUSP);    /* disable split screen */
  1055. X    setup_tty(TTY_SUSP);                /* put console back to original state */
  1056. X    if ((ff = fork()) == -1)            /* fork first child: if error, quit */
  1057. X        {
  1058. X        close(pipe_out[0]);
  1059. X        close(pipe_out[1]);
  1060. X        setup_tty(TTY_RESUME);
  1061. X        if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
  1062. X        ERROR(E_SYS);
  1063. X        }
  1064. X
  1065. X    if (ff)                            /* if this is the parent, the task is to read into q# */
  1066. X        {
  1067. X        make_buffer(&timbuf);        /* initialize the q# header */
  1068. X        bb.p = timbuf.f;            /* init bb to point to q# */
  1069. X        timbuf.z =     bb.c = 0;
  1070. X
  1071. X        close(pipe_out[1]);            /* parent won't write to this pipe */
  1072. X
  1073. X        if ((xx_out = fdopen(pipe_out[0], "r")) == 0)    /* open the "std out" pipe for reading */
  1074. X            {
  1075. X            close(pipe_out[0]);        /* if can't open output pipe */
  1076. X            setup_tty(TTY_RESUME);
  1077. X            if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
  1078. X            ERROR(E_SYS);            /* "open" failure */
  1079. X            }
  1080. X        read_stream(xx_out, 0, &bb, &timbuf.z, 0, 0, 1);        /* read from pipe to q# */
  1081. X        close(pipe_out[0]);
  1082. X
  1083. X        while (wait(&status) != ff);        /* wait for children to finish */
  1084. X        setup_tty(TTY_RESUME);
  1085. X        if (win_data[7]) window(WIN_RESUME), window(WIN_REDRAW);
  1086. X        return(status.w_retcode ? -1 : 0);
  1087. X        }
  1088. X /* This is the child.  It in turn forks into two processes, of which the "parent"    */
  1089. X/* (original child) writes the specified part of the buffer to the pipe, and the    */
  1090. X/* new child (grandchild to the original teco) execl's the Unix command.            */
  1091. X
  1092. X    else                            /* this is the child */
  1093. X        {
  1094. X        close(pipe_out[0]);                /* won't read from "output" pipe */
  1095. X        if (pipe(pipe_in)) exit(1);        /* make the "std in" pipe for the process, quit if can't */
  1096. X
  1097. X        if ((ff = fork()) == -1) exit(1);    /* fork to two processes (total 3), exit if error */
  1098. X
  1099. X        if (ff)                            /* parent - will send chars */
  1100. X            {
  1101. X            close(pipe_in[0]);            /* won't read from this pipe */
  1102. X
  1103. X        /* open pipe for writing; exit if open fails */
  1104. X
  1105. X            if ((xx_in = fdopen(pipe_in[1], "w")) == 0) exit(1);
  1106. X
  1107. X            write_stream(xx_in, &aa, ll, 0);        /* write to stream, CRLF becomes LF */
  1108. X            fclose(xx_in);
  1109. X
  1110. X            while (wait(&status) != ff);    /* wait for child */
  1111. X            exit(status.w_retcode);            /* exit with child's status */
  1112. X            }
  1113. X
  1114. X        else                            /* this process is the grandchild */
  1115. X            {
  1116. X            close(pipe_in[1]);            /* close "input" for writing */
  1117. X            dup2(pipe_in[0], fileno(stdin));        /* substitute pipe_in for stdin */
  1118. X            dup2(pipe_out[1], fileno(stdout));        /* and pipe_out for stdout    */
  1119. X            close(pipe_in[0]);            /* close original descriptors */
  1120. X            close(pipe_out[1]);
  1121. X
  1122. X            execl(shell, shell, "-c", &sysbuf.f->ch[0], 0);        /* execute specified routine */
  1123. X            fputs("execl failed\n", stderr);
  1124. X            exit(1);
  1125. X            }
  1126. X        }
  1127. X    }
  1128. X /* Routines to handle EN wild-card file specification    */
  1129. X/* ENfilespec$ defines file class, leaving 'filespec'    */
  1130. X/* in filespec buffer and reading expanded list of        */
  1131. X/* files into local buffer.  EN$ gets next filespec        */
  1132. X/* into filespec buffer.                                */
  1133. X
  1134. Xstruct qh en_buf;                /* header for storage for file list */
  1135. Xstruct qp en_ptr;                /* pointer to load/read file list    */
  1136. Xstatic char glob_cmd0[] = { 'g', 'l', 'o', 'b', ' ' } ;
  1137. X
  1138. Xint do_en()
  1139. X    {
  1140. X    int t;
  1141. X
  1142. X    if (build_string(&fbuf))                    /* if a file string is specified */
  1143. X        {
  1144. X        if (fbuf.z > CELLSIZE-2) ERROR(E_STL);        /* upper limit on string length */
  1145. X        fbuf.f->ch[fbuf.z] = '\0';                /* terminating null */
  1146. X        t = do_glob(&en_buf);                    /* glob the result */
  1147. X        en_ptr.p = en_buf.f;                    /* set the buffer pointer to the beginning of the buffer */
  1148. X        en_ptr.dot = en_ptr.c = 0;
  1149. X        }
  1150. X    else                                        /* if no string, get next filename */
  1151. X        {
  1152. X        do_en_next();
  1153. X        t = (fbuf.z) ? -1 : 0;                    /* t zero if no more filespecs */
  1154. X        if (!t && !colonflag) ERROR(E_NFI);        /* if no colon, end of spec is an error */
  1155. X        }
  1156. X    return (t);
  1157. X    }
  1158. X
  1159. X/* routine to expand the string in the filespec buffer */
  1160. X/* argument is the address of a qh that gets the expanded string */
  1161. X/* argument->v gets set to the number of file specs found */
  1162. X
  1163. Xint do_glob(buff)
  1164. X    struct qh *buff;
  1165. X    {
  1166. X    char glob_cmd[CELLSIZE+5];            /* "glob filespec" command string */
  1167. X    int t;
  1168. X    char c;
  1169. X    int glob_pipe[2];                    /* pipe to forked shell for expanding filenames */
  1170. X    struct qp glob_ptr;                    /* pointer for loading result buffer */
  1171. X    FILE *xx_out;                        /* stream for reading chars from pipe */
  1172. X    FILE *fdopen();
  1173. X    union wait status;
  1174. X
  1175. X    make_buffer(buff);                    /* initialize expanded file buffer */
  1176. X    glob_ptr.p = buff->f;                /* initialize pointer to buffer */
  1177. X    glob_ptr.c = glob_ptr.dot = buff->z = buff->v = 0;
  1178. X    for (t = 0; t < 5; t++) glob_cmd[t] = glob_cmd0[t];        /* set up "glob filespec" command */
  1179. X    for (t = 0; t < fbuf.z +1; t++) glob_cmd[t+5] = fbuf.f->ch[t];
  1180. X
  1181. X    if (pipe(glob_pipe)) ERROR(E_SYS);        /* make a pipe */
  1182. X    setup_tty(TTY_SUSP);                    /* put console back to normal */
  1183. X    if ((t = fork()) == -1)                    /* spawn a child... if failure */
  1184. X        {
  1185. X        close(glob_pipe[0]);                /* undo the pipe */
  1186. X        close(glob_pipe[1]);
  1187. X        setup_tty(TTY_RESUME);
  1188. X        ERROR(E_SYS);                        /* and exit with failure */
  1189. X        }
  1190. X
  1191. X    if (t)                                    /* if this is the parent */
  1192. X        {
  1193. X        close(glob_pipe[1]);                /* parent won't write */
  1194. X        if ((xx_out = fdopen(glob_pipe[0], "r")) == 0)    /* open pipe for read */
  1195. X            {
  1196. X            close(glob_pipe[0]);                        /* failure to open */
  1197. X            setup_tty(TTY_RESUME);
  1198. X            ERROR(E_SYS);
  1199. X            }
  1200. X
  1201. X        while ((c = getc(xx_out)) != EOF)        /* read characters from pipe */
  1202. X            {
  1203. X            if (c == '\0') ++buff->v;            /* count null chars that separate file specs */
  1204. X            glob_ptr.p->ch[glob_ptr.c] = c;        /* store them in buffer */
  1205. X            fwdcx(&glob_ptr);
  1206. X            }
  1207. X
  1208. X        fclose(xx_out);                            /* through with stream */
  1209. X        buff->z = glob_ptr.dot;                    /* save character count */
  1210. X        while (wait(&status) != t);                /* wait for child to finish */
  1211. X        setup_tty(TTY_RESUME);
  1212. X        return(status.w_retcode ? 0 : -1);        /* return success unless child exited nonzero */
  1213. X        }
  1214. X     else                                        /* this is the child */
  1215. X        {
  1216. X        close(glob_pipe[0]);                    /* child won't read */
  1217. X        dup2(glob_pipe[1], fileno(stdout));        /* substitute pipe for standard out */
  1218. X        close(glob_pipe[1]);                    /* don't need that anymore */
  1219. X        execl("/bin/csh", "csh", "-fc", glob_cmd, 0);        /* execute the "glob" */
  1220. X        fputs("execl failed\n", stderr);
  1221. X        exit(1);
  1222. X        }
  1223. X    }
  1224. X
  1225. X/* routine to get next file spec from "EN" list into filespec buffer */
  1226. X
  1227. Xdo_en_next()
  1228. X    {
  1229. X    char c;
  1230. X
  1231. X    make_buffer(&fbuf);                            /* initialize the filespec buffer */
  1232. X    fbuf.z = 0;
  1233. X
  1234. X    while(en_ptr.dot < en_buf.z)                /* stop at end of string */
  1235. X        {
  1236. X        c = en_ptr.p->ch[en_ptr.c];
  1237. X        fwdc(&en_ptr);
  1238. X        if (!c) break;                            /* null is terminator between file specs */
  1239. X        fbuf.f->ch[fbuf.z++] = c;                /* store char */
  1240. X        if (fbuf.z >= CELLSIZE-1) ERROR(E_STL);        /* limit on filespec size */
  1241. X        }
  1242. X
  1243. X    fbuf.f->ch[fbuf.z] = '\0';                    /* filespec ends with NULL */
  1244. X    }
  1245. X
  1246. X/* routine to read a file name                */
  1247. X/* reads it into fbuf text area                */
  1248. X/* returns nonzero if a name, 0 if none        */
  1249. X/* flag nonzero => empty name clears filespec buffer */
  1250. X/* func is 'r' for ER or EB cmds, 'i' for EI, 'w' for EW */
  1251. X
  1252. Xint read_filename(flag, func)
  1253. X    int flag;
  1254. X    char func;
  1255. X    {
  1256. X    int i, t, expand;
  1257. X    char c;
  1258. X    struct qh temp_buff;                        /* temp buffer for globbing filespec */
  1259. X
  1260. X    if (!(t = build_string(&fbuf)))                /* if no name spec'd */
  1261. X        {
  1262. X        if (flag) fbuf.z = 0;                    /* if no name spec'd, set length to 0 */
  1263. X        }
  1264. X    else
  1265. X        {
  1266. X        if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
  1267. X        fbuf.f->ch[fbuf.z] = '\0';                /* store terminating NULL */
  1268. X
  1269. X/* check for characters to be expanded by the shell */
  1270. X
  1271. X        for (i = 0; i < fbuf.z; i++)
  1272. X            if ((c = fbuf.f->ch[i]) == '*' || c == '?' || c == '[' || c == 0173) break;
  1273. X        if ( (expand = (i < fbuf.z)) || fbuf.f->ch[0] == '~')    /* one of these was found, or first char is ~ */
  1274. X            {
  1275. X            temp_buff.f = NULL;                    /* make a temp buffer to glob filename into */
  1276. X            make_buffer(temp_buff);
  1277. X            do_glob(&temp_buff);                /* expand the file name */
  1278. X            if (temp_buff.z == 0)                /* no match */
  1279. X                {
  1280. X                free_blist(temp_buff.f);        /* return the storage */
  1281. X                ERROR(func == 'w' ? E_COF : E_FNF);    /* "can't open" or "file not found" */
  1282. X                }
  1283. X            else if (temp_buff.v == 0)            /* if exactly one file name */
  1284. X                {
  1285. X                free_blist(fbuf.f);                /* return the old file spec */
  1286. X                fbuf.f = temp_buff.f;            /* put the temp buffer there instead */
  1287. X                fbuf.z = temp_buff.z;
  1288. X                if (fbuf.z > CELLSIZE-2) ERROR(E_STL);
  1289. X                fbuf.f->ch[fbuf.z] = '\0';
  1290. X
  1291. X                if (func == 'w' && expand)        /* if this is EW and 'twas from a wildcard expansion */
  1292. X                    {
  1293. X                    vt(VT_SETSPEC1);            /* "file XXXX already exists: overwrite? [yn]" */
  1294. X                    fputs("File ", stdout);
  1295. X                    fputs(fbuf.f->ch, stdout);
  1296. X                    fputs(" already exists: overwrite? [ny] ", stdout);
  1297. X                    vt(VT_CLRSPEC);
  1298. X                    c = gettty();                /* read user's response */
  1299. X                    putchar(CR);
  1300. X                    vt(VT_EEOL);                /* clean up the screen */
  1301. X                    if (c != 'y') ERROR(E_COF);    /* abort here */
  1302. X                    }
  1303. X                }
  1304. X
  1305. X            else                                /* multiple file specs */
  1306. X                {
  1307. X                if (func != 'r' || !(ez_val & EZ_MULT))                /* if multiple file specs here aren't allowed */
  1308. X                    {
  1309. X                    free_blist(temp_buff.f);            /* return the storage */
  1310. X                    ERROR(E_AMB);
  1311. X                    }
  1312. X                free_blist(en_buf.f);                    /* substitute the expansion for the "EN" list */
  1313. X                en_ptr.p = en_buf.f = temp_buff.f;        /* and initialize the "EN" list pointer */
  1314. X                en_buf.z = temp_buff.z;
  1315. X                en_ptr.dot = en_ptr.c = 0;
  1316. X                do_en_next();                    /* get the first file */
  1317. X                }
  1318. X            }
  1319. X        }
  1320. X    return(t);
  1321. X    }
  1322. X
  1323. X
  1324. X
  1325. X/* fetch or set variable */
  1326. X
  1327. Xset_var(arg)
  1328. X    int *arg;            /* argument is pointer to variable */
  1329. X    {
  1330. X    if (esp->flag1)        /* if an argument, then set the variable */
  1331. X        {
  1332. X        if (esp->flag2)                    /* if two arguments, then <clr>, <set> */
  1333. X            *arg = (*arg & ~esp->val2) | esp->val1;
  1334. X        else *arg = esp->val1;            /* one arg is new value */
  1335. X        esp->flag2 = esp->flag1 = 0;    /* consume argument */
  1336. X        }
  1337. X    else                /* otherwise fetch the variable's value */
  1338. X        {
  1339. X        esp->val1 = *arg;
  1340. X        esp->flag1 = 1;
  1341. X        }
  1342. X    }
  1343. X
  1344. X
  1345. X
  1346. X/* read from selected input file stream into specified buffer    */
  1347. X/* terminate on end-of-file or form feed                        */
  1348. X/* if endsw > 0 terminates after that many lines                */
  1349. X/* if endsw < 0 stops if z > BUFF_LIMIT                            */
  1350. X/* returns -1 if read EOF, 0 otherwise                            */
  1351. X
  1352. Xint read_file(buff, nchars, endsw)
  1353. X    struct qp *buff;
  1354. X    int *nchars, endsw;
  1355. X    {
  1356. X    if (!infile->fd) infile->eofsw = -1, ctrl_e = 0;    /* return if no input file open */
  1357. X    else infile->eofsw = read_stream(infile->fd, &ctrl_e, buff, nchars, endsw, ez_val & EZ_CRLF, ez_val & EZ_READFF);
  1358. X    return(esp->val1 = infile->eofsw);
  1359. X    }
  1360. X /* read from an I/O stream into specified buffer                            */
  1361. X/* this is used by read_file and by "eq" pipe from other Unix processes        */
  1362. X/* args buff, nchars, endsw as above; file is stream pointer, ff_found is    */
  1363. X/* address of a switch to set if read ended with a FF, crlf_sw is lf->crlf    */
  1364. X/* conversion, ff_sw indicates whether to stop on a form feed.                */
  1365. X
  1366. Xint read_stream(file, ff_found, buff, nchars, endsw, crlf_sw, ff_sw)
  1367. X    FILE *file;
  1368. X    struct qp *buff;
  1369. X    int *ff_found, *nchars, endsw, crlf_sw, ff_sw;
  1370. X    {
  1371. X    char chr;
  1372. X    int crflag;
  1373. X    register struct buffcell *p;
  1374. X    register int c;
  1375. X
  1376. X    p = (*buff).p;        /* copy pointer locally */
  1377. X    c = (*buff).c;
  1378. X    crflag = 0;            /* "last char wasn't CR" */
  1379. X    while (((chr = getc(file)) != EOF) && ((chr != FF) || ff_sw))
  1380. X        {
  1381. X        if ((chr == LF) && !crflag && !crlf_sw)        /* automatic cr before lf */
  1382. X            {
  1383. X            p->ch[c] = CR;        /* store a cr */
  1384. X            ++(*nchars);        /* increment buffer count */
  1385. X            if (++c > CELLSIZE-1)    /* next cell? */
  1386. X                {
  1387. X                if (!p->f)            /* need a new cell? */
  1388. X                    {
  1389. X                    p->f = get_bcell();
  1390. X                    p->f->b = p;
  1391. X                    }
  1392. X                p = p->f;
  1393. X                c = 0;
  1394. X                }
  1395. X            }
  1396. X        p->ch[c] = chr;            /* store char */
  1397. X        ++(*nchars);            /* increment character count */
  1398. X        if (++c > CELLSIZE-1)    /* next cell? */
  1399. X            {
  1400. X            if (!p->f)            /* need a new cell? */
  1401. X                {
  1402. X                p->f = get_bcell();
  1403. X                p->f->b = p;
  1404. X                }
  1405. X            p = p->f;
  1406. X            c = 0;
  1407. X            }
  1408. X        crflag = (chr == CR);    /* flag set if last char was CR */
  1409. X        if ((chr == LF) && ((endsw < 0 && z > BUFF_LIMIT) || (endsw > 0 && --endsw == 0))) break;    /* term after N lines */
  1410. X        }
  1411. X    (*buff).p = p;            /* update pointer */
  1412. X    (*buff).c = c;
  1413. X    if (ff_found) *ff_found = (chr == FF) ? -1 : 0;        /* set flag to indicate whether FF found */
  1414. X    return( (chr == EOF) ? -1 : 0);                    /* and return "eof found" value */
  1415. X    }
  1416. X /* routine to write text buffer out to selected output file    */
  1417. X/* arguments are qp to start of text, number of characters,    */
  1418. X/* and an "append FF" switch                                */
  1419. X
  1420. Xwrite_file(buff, nchars, ffsw)
  1421. X    struct qp *buff;
  1422. X    int nchars, ffsw;
  1423. X    {
  1424. X    if (!outfile->fd && (nchars)) ERROR(E_NFO);
  1425. X    else write_stream(outfile->fd, buff, nchars, ez_val & EZ_CRLF);
  1426. X    if (outfile->fd && ffsw) putc(FF, outfile->fd);
  1427. X    }
  1428. X
  1429. X
  1430. X/* routine to write text buffer to I/O stream.  Used by    */
  1431. X/* write_file, above, and by "eq" write to pipe to other    */
  1432. X/* Unix processes.  Arguments buff, nchars as above; file    */
  1433. X/* is stream pointer, crlf_sw zero converts CRLF to LF        */
  1434. X
  1435. Xwrite_stream(file, buff, nchars, crlf_sw)
  1436. X    FILE *file;
  1437. X    struct qp *buff;
  1438. X    int nchars, crlf_sw;
  1439. X    {
  1440. X    char c;
  1441. X    int crflag;
  1442. X
  1443. X    crflag = 0;
  1444. X    for (; nchars > 0; nchars--)
  1445. X        {
  1446. X        if ((c = (*buff).p->ch[(*buff).c]) == CR) crflag = 1;    /* set flag if a c.r. */
  1447. X        else
  1448. X            {
  1449. X            if ((crflag) && ((c != LF) || crlf_sw))            /* if c.r. not before lf, or if not in */
  1450. X                putc(CR, file);                                /* "no cr" mode, output the c.r. */
  1451. X            crflag = 0;
  1452. X            putc(c, file);
  1453. X            }
  1454. X        if (++(*buff).c > CELLSIZE-1)
  1455. X            {
  1456. X            (*buff).p = (*buff).p->f;
  1457. X            (*buff).c = 0;
  1458. X            }
  1459. X        }
  1460. X    }
  1461. X
  1462. X
  1463. X/* routine to kill output file: argument is pointer to an output file structure */
  1464. X
  1465. Xkill_output(outptr)
  1466. X    struct outfiledata *outptr;
  1467. X    {
  1468. X    if (outptr->fd)
  1469. X        {
  1470. X        fclose(outptr->fd);
  1471. X        unlink(outptr->t_name);
  1472. X        outptr->fd = NULL;
  1473. X        }
  1474. X    }
  1475. X /* "panic" routine called when "hangup" signal occurs */
  1476. X/* this routine saves the text buffer and closes the output files */
  1477. X
  1478. Xchar panic_name[] = "TECO_SAVED.tmp";            /* name of file created to save buffer */
  1479. X
  1480. Xpanic()
  1481. X    {
  1482. X    if (!outfile->fd && z) outfile->fd = fopen(panic_name, "w");    /* if buffer nonempty and no file open, make one */
  1483. X
  1484. X    set_pointer(0, &aa);                                /* set a pointer to start of text buffer */
  1485. X    if (outfile->fd && z) write_file(&aa, z, 0);        /* and write out buffer unless "open" failed */
  1486. X
  1487. X    if (po_file.fd) fclose(po_file.fd), po_file.fd = NULL;        /* close any open output files */
  1488. X    if (so_file.fd) fclose(so_file.fd), so_file.fd = NULL;
  1489. X    }
  1490. X /* do "F" commands */
  1491. X
  1492. Xdo_f()
  1493. X    {
  1494. X    struct buffcell *delete_p;
  1495. X
  1496. X    switch (mapch_l[getcmdc(trace_sw)])         /* read next character and dispatch */
  1497. X        {
  1498. X        case '<':            /* back to beginning of current iteration */
  1499. X            if (cptr.flag & F_ITER)        /* if in iteration */
  1500. X                {
  1501. X                cptr.p = cptr.il->p;    /* restore */
  1502. X                cptr.c = cptr.il->c;
  1503. X                cptr.dot = cptr.il->dot;
  1504. X                }
  1505. X            else for (cptr.dot = cptr.c = 0; cptr.p->b->b != NULL; cptr.p = cptr.p->b);    /* else, restart current macro */
  1506. X            break;
  1507. X
  1508. X        case '>':            /* to end of current iteration */
  1509. X            find_enditer();    /* find it */
  1510. X            if ( ( ((esp->flag1) ? esp->val1 : srch_result) >= 0) ? (~colonflag) : colonflag)    /* if exit */
  1511. X            pop_iteration(0);    /* and exit if appropriate */
  1512. X            break;
  1513. X
  1514. X        case '\'':                    /* to end of conditional */
  1515. X        case '|':                    /* to "else," or end */
  1516. X            find_endcond(cmdc);
  1517. X            break;
  1518. X
  1519. X/* "F" search commands */
  1520. X
  1521. X        case 'b':                        /* bounded search, alternative args */
  1522. X            do_fb();
  1523. X            break;
  1524. X
  1525. X        case 'c':                        /* bounded search, alternative args, then "FR" */
  1526. X            if (do_fb()) goto do_fr;
  1527. X            while (getcmdc(trace_sw) != term_char);        /* otherwise skip insert string */
  1528. X            break;
  1529. X
  1530. X        case 'n':                        /* do "N" and then "FR" */
  1531. X            if (do_nsearch('n')) goto do_fr;
  1532. X            while (getcmdc(trace_sw) != term_char);        /* otherwise skip insert string */
  1533. X            break;
  1534. X
  1535. X        case '_':                        /* do "_" and then "FR" */
  1536. X            if (do_nsearch('_')) goto do_fr;
  1537. X            while (getcmdc(trace_sw) != term_char);        /* otherwise skip insert string */
  1538. X            break;
  1539. X
  1540. X        case 's':                        /* search and replace: search, then do "FR" */
  1541. X            build_string(&sbuf);        /* read search string and terminator */
  1542. X            if (end_search(  do_search( setup_search() )  )) goto do_fr;    /* if search passed, do "FR" */
  1543. X            while (getcmdc(trace_sw) != term_char);        /* otherwise skip insert string */
  1544. X            break;
  1545. X         case 'r':                        /* replace last insert, search, etc. */
  1546. X            if (esp->flag1) ERROR(E_NFR);    /* shouldn't have argument */
  1547. X            term_char = (atflag) ? getcmdc(trace_sw) : ESC;        /* set terminator */
  1548. X            atflag = 0;
  1549. X          do_fr:                    /* entry from FN, F_, and FC */
  1550. X            set_pointer(dot, &cc);        /* save a pointer to the current spot */
  1551. X            dot += ctrl_s;                /* back dot up over the string */
  1552. X            set_pointer(dot, &aa);        /* code from "insert1": convert dot to a qp */
  1553. X            delete_p = aa.p;            /* save beginning of original cell */
  1554. X            if (dot < buff_mod) buff_mod = dot;        /* update earliest char loc touched */
  1555. X            insert_p = bb.p = get_bcell();            /* get a new cell */
  1556. X            bb.c = 0;
  1557. X            ins_count = aa.c;        /* save char position of dot in cell */
  1558. X            aa.c = 0;
  1559. X
  1560. X            movenchars(&aa, &bb, ins_count);    /* copy cell up to dot */
  1561. X            moveuntil(&cptr, &bb, term_char, &ins_count, cptr.z-cptr.dot, trace_sw);    /* insert */
  1562. X            cptr.dot += ins_count;        /* advance command-string pointer */
  1563. X            getcmdc(trace_sw);            /* skip terminator */
  1564. X
  1565. X            z += ctrl_s;                /* subtract delete length from buffer count */
  1566. X            delete_p->b->f = insert_p;    /* put the new cell where the old one was */
  1567. X            insert_p->b = delete_p->b;    /* code borrowed from "insert2" */
  1568. X            insert_p = NULL;
  1569. X
  1570. X            if (bb.c == cc.c)            /* if replacement text was same length, we can save time */
  1571. X                {
  1572. X                for (; bb.c < CELLSIZE; bb.c++) bb.p->ch[bb.c] = cc.p->ch[bb.c];    /* copy rest of cell */
  1573. X                bb.p->f = cc.p->f;        /* replace orig cell's place in chain with end of new list */
  1574. X                if (bb.p->f) bb.p->f->b = bb.p;
  1575. X                cc.p->f = NULL;            /* terminate the part snipped out */
  1576. X                free_blist(delete_p);    /* return the old part */
  1577. X                }
  1578. X
  1579. X            else                        /* different positions: shift the remainder of the buffer */
  1580. X                {
  1581. X                bb.p->f = delete_p;        /* splice rest of buffer to end */
  1582. X                delete_p->b = bb.p;
  1583. X                movenchars(&cc, &bb, z-dot);    /* squeeze buffer */
  1584. X                free_blist(bb.p->f);        /* return unused cells */
  1585. X                bb.p->f = NULL;                /* and end the buffer */
  1586. X                }
  1587. X
  1588. X            z += ins_count;                /* add # of chars inserted */
  1589. X            dot += ins_count;
  1590. X            ctrl_s = -ins_count;        /* save string length */
  1591. X            esp->flag1 = esp->flag2 = 0;    /* and consume arguments */
  1592. X            esp->op = OP_START;
  1593. X            break;
  1594. X
  1595. X        default:
  1596. X            ERROR(E_IFC);
  1597. X        }
  1598. X    }
  1599. X /* routines for macro iteration */
  1600. X/* pop iteration: if arg nonzero, exit unconditionally */
  1601. X/* else check exit conditions and exit or reiterate */
  1602. X
  1603. Xpop_iteration(arg)
  1604. X    int arg;
  1605. X    {
  1606. X    if (!arg && (!cptr.il->dflag || (--(cptr.il->count) > 0)) )        /* if reiteration */
  1607. X        {
  1608. X        cptr.p = cptr.il->p;        /* restore */
  1609. X        cptr.c = cptr.il->c;
  1610. X        cptr.dot = cptr.il->dot;
  1611. X        }
  1612. X    else
  1613. X        {
  1614. X        if (cptr.il->b) cptr.il = cptr.il->b;    /* if not last thing on stack, back up */
  1615. X        else cptr.flag &= ~F_ITER;                /* else clear "iteration" flag */
  1616. X        }
  1617. X    }
  1618. X
  1619. X
  1620. X/* find end of iteration - read over arbitrary <> and one > */
  1621. X
  1622. Xfind_enditer()
  1623. X    {
  1624. X    register int icnt;
  1625. X
  1626. X    for (icnt = 1; icnt > 0;)        /* scan for matching > */
  1627. X        {
  1628. X        while ((skipto(0) != '<') && (skipc != '>'));    /* scan for next < or > */
  1629. X        if (skipc == '<') ++icnt;        /* and keep track of macro level */
  1630. X        else --icnt;
  1631. X        }
  1632. X    }
  1633. X
  1634. X
  1635. X
  1636. X/* find end of conditional */
  1637. Xchar find_endcond(arg)
  1638. X    char arg;
  1639. X    {
  1640. X    register int icnt;
  1641. X
  1642. X    for (icnt = 1; icnt > 0;)
  1643. X        {
  1644. X        while ((skipto(0) != '"') && (skipc != '\'') && (skipc != '|'));
  1645. X        if (skipc == '"') ++icnt;
  1646. X        else if (skipc == '\'') -- icnt;
  1647. X        else if ((icnt == 1) && (arg == '|')) break;
  1648. X        }
  1649. X    }
  1650. X
  1651. END_OF_te_exec2.c
  1652. if test 29256 -ne `wc -c <te_exec2.c`; then
  1653.     echo shar: \"te_exec2.c\" unpacked with wrong size!?
  1654. fi
  1655. # end of overwriting check
  1656. fi
  1657. echo shar: End of archive 3 \(of 4\).
  1658. cp /dev/null ark3isdone
  1659. DONE=true
  1660. for I in 1 2 3 4 ; do
  1661.     if test ! -f ark${I}isdone ; then
  1662.     echo shar: You still need to run archive ${I}.
  1663.     DONE=false
  1664.     fi
  1665. done
  1666. if test "$DONE" = "true" ; then
  1667.     echo You have unpacked all 4 archives.
  1668.     echo "See the *.doc files"
  1669.     rm -f ark[1-9]isdone
  1670. fi
  1671. ##  End of shell archive.
  1672. exit 0
  1673.